package scheduletask;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.testng.annotations.Test;

public class Case1 {


    public static Case1 INSTANCE = new Case1();

    /**
     * 定时任务执行间隔，单位：秒
     */
    private static final int INTERVAL = 1;

    private static List<LampTask> taskList = new ArrayList<>();

    /**
     * 类加载的时候初始化
     */
    private ScheduledThreadPoolExecutor threadPoolExecutor = new ScheduledThreadPoolExecutor(1,
        new ThreadFactoryBuilder().setNameFormat("lamp-executor-%d").setDaemon(false).build());

    /**
     * 用于当有新任务到来是取消所有旧的定时任务
     */
    private ScheduledFuture<?> scheduledFuture;

    /**
     * 跑马灯任务对象
     */
    static class LampTask {

        /**
         * 跑马灯内容
         */
        private String context;

        /**
         * 总执行次数，根据设置的 开始-结束时间-执行间隔 计算出来
         */
        private int count;

        /**
         * 执行间隔
         */
        private int period;

        /**
         * 距下一次执行的倒计时，单位秒
         */
        private int countdown;

        public LampTask(String context, int count, int period, int countdown) {
            this.context = context;
            this.count = count;
            this.period = period;
            this.countdown = countdown;
        }

        public String getContext() {
            return context;
        }

        public void setContext(String context) {
            this.context = context;
        }

        public int getCount() {
            return count;
        }

        public void setCount(int count) {
            this.count = count;
        }

        public int getPeriod() {
            return period;
        }

        public void setPeriod(int period) {
            this.period = period;
        }

        public int getCountdown() {
            return countdown;
        }

        public void setCountdown(int countdown) {
            this.countdown = countdown;
        }

        @Override public String toString() {
            return "LampTask{" + "context='" + context + '\'' + ", count=" + count + ", period=" + period
                + ", countdown=" + countdown + '}';
        }
    }



    private static void sendHorseLamp(String content, long startTime, long endTime, int period) {
        if (Objects.isNull(INSTANCE.threadPoolExecutor)) {
            INSTANCE.threadPoolExecutor = new ScheduledThreadPoolExecutor(1,
                            new ThreadFactoryBuilder().setNameFormat("lamp-executor-%d").setDaemon(false).build());
        }

//        long delay = (startTime - System.currentTimeMillis()) / 1000;




    }

    private static Runnable forkJoinTask(String content, long startTime, long endTime, int period) {

        // 是动态执行，不会一次就把所有的任务都提交
        return () -> {
            // 当前必定要发出跑马灯，然后判断下一次是否需要发出
            System.out.println("send horse lamp" + content);
            // 当前任务下一次执行时间是否如果超过了结束时间，就关掉执行器，本次任务的开始时间、结束时间，本次任务已经在
            boolean isNeedShutdownExecutor = System.currentTimeMillis() + period > endTime;

            if (isNeedShutdownExecutor) {

                // 这是为了关闭前面所有的任务，不能够直接关掉执行器，要考虑后续有无任务; 不要shutdown
                INSTANCE.threadPoolExecutor.shutdown();
            } else {
                // 当前任务没有结束，并且有有任务到来，就要启动新的任务

                // 这并不是递归，因为
                INSTANCE.threadPoolExecutor.schedule(forkJoinTask(content, startTime, endTime, period), period, TimeUnit.SECONDS);
            }
        };


//        INSTANCE.threadPoolExecutor.schedule(r, 0, TimeUnit.SECONDS);


//        sendHorseLamp(content, startTime, endTime, period);
    }




//    public static void sendHorseLamp(String content, long startTime, long endTime, int period) {
//
//
//
////        var executor = new ScheduledThreadPoolExecutor(1,
////            new ThreadFactoryBuilder().setNameFormat("lamp-executor-%d").setDaemon(false).build());
//
//        // Runnable是执行起来是动态的，
//
//    }

    public static void main(String[] args) throws InterruptedException {


        sendHorseLamp("123", 1647423539000L, 1647423839000L, 5);

        Thread.sleep(1000 * 3000);

        // 模拟发跑马灯请求
//        LampTask task1 = new LampTask("task 1", 4, 1, 1);
//
//        LampTask task2 = new LampTask("task 2", 4, 2, 2);
//        LampTask task3 = new LampTask("task 3", 4, 3, 3);
//        LampTask task4 = new LampTask("task 4", 4, 4, 4);
//
//        taskList.add(task1);
////        taskList.add(task2);
////        taskList.add(task3);
////        taskList.add(task4);
//
//        INSTANCE.executorTask();
//
//        // 模拟到下一次发跑马灯的间隔
//        Thread.sleep(1000 * 10);
//
//        System.out.println("second case exe");
//
//        // 模拟发跑马灯请求
//        LampTask task5 = new LampTask("task 1", 4, 1, 1);
//        taskList.add(task5);
//        INSTANCE.executorTask();

    }


    /**
     * 添加任务的时候调用一下
     */
    private void executorTask() {

        // 每当有新跑马灯，就结束掉已提交的定时任务，重新开始

//        threadPoolExecutor.shutdown();
        // cancel 有时会失败，抛出异常，

        if (!Objects.isNull(scheduledFuture)) {
            System.out.println("schedule cancel");
            scheduledFuture.cancel(true);
        }

        if (Objects.isNull(threadPoolExecutor) || threadPoolExecutor.isShutdown()) {
            threadPoolExecutor = new ScheduledThreadPoolExecutor(1,
                new ThreadFactoryBuilder().setNameFormat("lamp-executor-%d").setDaemon(false).build());
        }

        Runnable r = () -> {
            for (int i = 0; i < taskList.size(); i++) {
                var task = taskList.get(i);

                task.setCountdown(task.getCountdown() - INTERVAL);

                // 会出现倒计时小于0的情况
                if (task.getCountdown() <= 0) {

                    // 可执行次数 -1
                    task.setCount(task.getCount() - 1);

                    if (task.getCount() != 0) {
                        task.setCountdown(task.getPeriod());
                    } else {
                        taskList.remove(task);
                    }

                    // 发送跑马灯
                    System.out.println(task + ", size " + taskList.size() + " 执行的时间 " + LocalTime.now());
                // 未达到执行条件，更新倒计时
                } else {
                    task.setCountdown(task.getCountdown() - INTERVAL);
                }
            }

            if (taskList.size() == 0) {
                System.out.println("shutdown execution");
                // 执行shutdown之后再添加任务会执行拒绝策略，抛出异常 RejectedExecutionException
                threadPoolExecutor.shutdown();
            }
        };

        // 每 INTERVAL 秒钟执行一次，启动定时任务时更新future
        scheduledFuture = threadPoolExecutor.scheduleAtFixedRate(r, 0, INTERVAL, TimeUnit.SECONDS);

        // 如果没有任务了，把定时任务停掉，这些会在定时任务之前执行
//        System.out.println("元素数量 " + INSTANCE.size());
//        if (INSTANCE.size() == 0) {
//            System.out.println("shutdown execution");
//            threadPoolExecutor.shutdown();
//        }
    }

    private void addTAsk() {

        if (threadPoolExecutor.isShutdown()) {

        }

        LampTask task = new LampTask("task 4", 5, 4, 4);
        taskList.add(task);


    }

    /**
     * 遍历修改
     */
    @Test(invocationCount = 5)
    private void t1() {
        var list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        // 用for循环可以，因为没有使用iterator
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
            list.remove(list.get(i));
            System.out.println(list);
        }

//        list.forEach(num -> {
//            System.out.println(num);
//            list.remove(num);
//            System.out.println(list);
//        });
    }


    @Test
    private void t3() {
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
        executor.schedule(() -> System.out.println("延迟时间为负数，立即执行"), -10, TimeUnit.SECONDS);

    }

}
